﻿using System.Linq.Expressions;

namespace MiniJob.Service;

public interface IBaseService<TEntity> where TEntity : Entity.Entity
{
    Task<List<TEntity>> AllAsync();

    Task<TEntity> GetAsync(Guid id);

    Task UpdateAsync(TEntity entity);

    Task UpdateAsync(IList<TEntity> entities);

    Task DeleteAsync(Guid id);

    Task DeleteAsync(TEntity entity);

    Task DeleteAsync(IList<TEntity> entities);

    Task<TEntity> InsertAsync(TEntity entity);

    Task InsertAsync(IList<TEntity> entities);

    Task<List<TEntity>> QueryAsync(Expression<Func<TEntity, bool>> exp);

    Task<List<TEntity>> QueryPageAsync(Expression<Func<TEntity, bool>> exp, int pageIndex, int pageSize,
        string defaultSortField = "Id", string defaultSortType = "ASC");

    Task<long> CountAsync(Expression<Func<TEntity, bool>>? exp = null);
}

public abstract class BaseService<TEntity>(IFreeSql freeSql) : IBaseService<TEntity> where TEntity : Entity.Entity
{
    protected IFreeSql FreeSql => freeSql;

    public Task<List<TEntity>> AllAsync()
    {
        return freeSql.Select<TEntity>().ToListAsync();
    }

    public Task<long> CountAsync(Expression<Func<TEntity, bool>>? exp = null)
    {
        return freeSql.Select<TEntity>().WhereIf(exp != null, exp).CountAsync();
    }

    public Task DeleteAsync(Guid id)
    {
        return freeSql.Delete<TEntity>().Where(p => p.Id == id).ExecuteAffrowsAsync();
    }

    public Task DeleteAsync(TEntity entity)
    {
        return freeSql.Delete<TEntity>().Where(p => p.Id == entity.Id).ExecuteAffrowsAsync();
    }

    public Task DeleteAsync(IList<TEntity> entities)
    {
        var ids = entities.Select(p => p.Id).ToList();
        return freeSql.Delete<TEntity>().Where(p => ids.Contains(p.Id)).ExecuteAffrowsAsync();
    }

    public Task<TEntity> GetAsync(Guid id)
    {
        return freeSql.Select<TEntity>()
            .Where(p => p.Id == id)
            .FirstAsync();
    }

    public async Task<TEntity> InsertAsync(TEntity entity)
    {
        _ = await freeSql.Insert(entity).ExecuteAffrowsAsync();
        return entity;
    }

    public Task InsertAsync(IList<TEntity> entities)
    {
        return freeSql.Insert(entities).ExecuteAffrowsAsync();
    }

    public Task<List<TEntity>> QueryAsync(Expression<Func<TEntity, bool>> exp)
    {
        return freeSql.Select<TEntity>().Where(exp).ToListAsync();
    }

    public Task<List<TEntity>> QueryPageAsync(Expression<Func<TEntity, bool>> exp, int pageIndex, int pageSize, 
        string defaultSortField = "Id", string defaultSortType = "ASC")
    {
        return freeSql.Select<TEntity>()
            .Where(exp)
            .OrderByPropertyName(defaultSortField, defaultSortType.Equals("ASC", StringComparison.OrdinalIgnoreCase))
            .Skip((pageIndex - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync();
    }

    public Task UpdateAsync(TEntity entity)
    {
        return freeSql.Update<TEntity>().SetSource(entity).ExecuteAffrowsAsync();
    }

    public Task UpdateAsync(IList<TEntity> entities)
    {
        return freeSql.Update<TEntity>().SetSource(entities).ExecuteAffrowsAsync();
    }
}
